﻿using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace SocketClient
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        Socket socket;
        Socket receiveSocket;
        string exceptionMsg;
        bool exceptionClass;
        CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();

        private async void  button1_Click(object sender, EventArgs e)
        {
            try
            {
                if (button1.Text == "连接服务器")
                {
                    await Connect();
                }
                else {
                    cancellationTokenSource.Cancel();
                    socket?.Send(Encoding.Default.GetBytes("close"));
                    socket?.Close();
                    button1.Text ="连接服务器";
                }

            }
            catch (Exception ex){
                button1.Text = "连接服务器";
                MessageBox.Show(ex.ToString());
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            try {
                string sendContent = messageSendTextBox.Text.Trim();
                socket.Send(Encoding.Default.GetBytes(sendContent));
                messageShowTextBox.AppendText($"[{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}]：{sendContent}-发送成功\r\n");
                messageSendTextBox.Text = "";
            }
            catch (Exception ex){
                MessageBox.Show(ex.Message);
            }
        }
        public async Task Connect() {
            try {
                Task task = Task.Run(() => {
                    try {
                        //this.Invoke(new Action(() => { button1.Text = "断开连接"; }));
                        if (IPtextBox.Text == "" || textBox1.Text == "")
                            throw new Exception();
                        socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                        socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); // 允许重用地址  
                        IPAddress address = IPAddress.Parse(IPtextBox.Text.Trim());
                        IPEndPoint endPoint = new IPEndPoint(address, int.Parse(textBox1.Text.Trim()));
                        socket.Connect(endPoint);
                        this.Invoke(new Action(() => {
                            button1.Text = "断开连接";
                            messageShowTextBox.AppendText($"[{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}]：服务器连接成功" + Environment.NewLine);
                        }));
                        //接收服务端消息
                        Task.Factory.StartNew(() => { receiveMessage(socket); }, cancellationTokenSource.Token);
                    } catch (Exception ex) {
                        if (ex.GetType() == typeof(Exception))
                        {
                            task = null;
                        }
                        else {
                            exceptionClass = true;
                            exceptionMsg = ex.Message;
                        }
                    }
                });
                await task;
                if (task == null)
                {
                    throw new Exception("IP或者端口不能为空");
                }
                if (exceptionClass) {
                    exceptionClass = false;
                    throw new Exception(exceptionMsg);
                }
                
            } catch (Exception ex) {
                MessageBox.Show(ex.Message);                
            }
            
        }
        public void receiveMessage(Socket socket) {
            byte[] bytes = new byte[1024];
            while (true)
            {
                if (cancellationTokenSource.IsCancellationRequested) {
                    break;
                }
                int len = socket.Receive(bytes);
                if (Encoding.Default.GetString(bytes, 0, len) == "close")
                {
                    this.Invoke(new Action(() => {
                        messageShowTextBox.AppendText($"[{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}]：服务端关闭\r\n");
                        button1.Text = "连接服务器";
                    }));
                    socket.Close();
                    break;
                }
            }
        }
    }
}
